home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 8: LINUX Games / Linux Cubed Series 8 - LINUX Games.iso / games / video / fly8111-.000 / fly8111- / fly8 / COMMON / stick.c < prev    next >
C/C++ Source or Header  |  1995-08-28  |  13KB  |  629 lines

  1. /* --------------------------------- stick.c -------------------------------- */
  2.  
  3. /* This is part of the flight simulator 'fly8'.
  4.  * Author: Eyal Lebedinsky (eyal@ise.canberra.edu.au).
  5. */
  6.  
  7. /* Handler for the PC joystick as a pointing device. On port A It will
  8.  * read the analog hat if it is present and will read all four buttons.
  9.  * Use of options:
  10.  *
  11.  *  0    analog 1 direction        p,n
  12.  *  1    what analog 1 controls        0,1
  13.  *  2    analog 2 direction        p,n
  14.  *  3    what analog 2 controls        0,1
  15.  *  4    number of times to read        0-36
  16.  *  5    delay between reads        0-36
  17.  *  6    analog 1 base            0-10
  18.  *  7    analog 2 base            0-10
  19.  *  8    analog 3 base            0-10
  20.  *  9    analog 4 base            0-10 (hat, throttle etc.)
  21. */
  22.  
  23. #include "fly.h"
  24.  
  25. #ifdef HAVE_JOYSTICK
  26.  
  27. #include "stick.h"
  28.  
  29.  
  30. #define PO        p->opt
  31. #define FA1D        PO[0]
  32. #define FA1F        PO[1]
  33. #define FA2D        PO[2]
  34. #define FA2F        PO[3]
  35. #define FNREAD        PO[4]
  36. #define FDELAY        PO[5]
  37. #define FA1IDLE        PO[6]
  38. #define FA1BASE        PO[7]
  39. #define FA1TOP        PO[8]
  40. #define FA2IDLE        PO[9]
  41. #define FA2BASE        PO[10]
  42. #define FA2TOP        PO[11]
  43. #define FA3IDLE        PO[12]
  44. #define FA3BASE        PO[13]
  45. #define FA3TOP        PO[14]
  46. #define FA4IDLE        PO[15]
  47. #define FA4BASE        PO[16]
  48. #define FA4TOP        PO[17]
  49. #define FOPTS        PO[18]
  50.  
  51. #define    REF        100        /* expected full range */
  52. #define    REFDETENT    75        /* Fly8 AB detent position */
  53.  
  54. /* Second level joystick input: apply 'nread' and 'ndelay'.
  55. */
  56.  
  57. LOCAL_FUNC int NEAR
  58. JsInput (int which, STICK *s, int opts, Ushort mask, Ushort nread,
  59.     Ushort delay)
  60. {
  61.     Uint    m, js, minx1, miny1, minx2, miny2, ntimes;
  62.     int    i, t;
  63.  
  64.     minx1 = miny1 = minx2 = miny2 = 0xffffU;
  65.  
  66.     for (ntimes = 0;;) {
  67.         m = readstick (which, s, mask, opts);
  68.         if (minx1 > s->a[0])
  69.             minx1 = s->a[0];
  70.         if (miny1 > s->a[1])
  71.             miny1 = s->a[1];
  72.         if (minx2 > s->a[2])
  73.             minx2 = s->a[2];
  74.         if (miny2 > s->a[3])
  75.             miny2 = s->a[3];
  76.  
  77.         if (++ntimes >= nread)        /* read more? */
  78.             break;
  79.  
  80.         if (T(i = delay)) {        /* delay? */
  81.             t = 1234;
  82.             for (i *= 10; i-- > 0;)
  83.                 t *= 19;
  84.         }
  85.     }
  86.  
  87.     js = m | ~mask;
  88.     s->a[0] = (Ushort)((js & JS_X1) ? 0 : minx1);
  89.     s->a[1] = (Ushort)((js & JS_Y1) ? 0 : miny1);
  90.     s->a[2] = (Ushort)((js & JS_X2) ? 0 : minx2);
  91.     s->a[3] = (Ushort)((js & JS_Y2) ? 0 : miny2);
  92.     
  93.     return (m);
  94. }
  95.  
  96.  
  97. /* Third level joystick input: interpret the raw input and adjust for
  98.  * calibration.
  99. */
  100.  
  101.  
  102. /* Interpret the joystick reading as symm_etric -100...+100.
  103.  * The 'base' parameter is interpreted as a fraction of the center reading.
  104. */
  105. LOCAL_FUNC void NEAR
  106. JsSymm (POINTER *p, int channel, int reading, int sign, int base, int top,
  107.     int transfer)
  108. {
  109.     int    center;
  110.     int    play;
  111.  
  112.     center = p->c[channel];
  113.     play   = p->play[channel];
  114.  
  115.     if (reading < (base += (play >> 1)))
  116.         reading = -100;
  117.     else if (reading < (center -= play))
  118.         reading = muldiv (-100, center - reading, center - base);
  119.     else if (reading < (center += play+play))
  120.         reading = 0;
  121.     else if (reading < (top -= (play >> 1)))
  122.         reading = muldiv (100, reading - center, top - center);
  123.     else
  124.         reading = 100;
  125.  
  126.     reading *= sign;                /* orientation */
  127.  
  128.     p->a[channel] = (short)reading;
  129.     if (transfer)
  130.         p->l[channel] = (short)((FOPTS & USELOG)
  131.                     ? lin2log ((short)reading) : reading);
  132. }
  133.     
  134. /* Interpret the joystick reading as 'hat' position.
  135.  * The 'base' parameter is interpreted as a fraction of the center reading.
  136.  * the reading is spread evenly from 0 to 100 and has the following states
  137.  * in order: 0=up, 25=right, 50=down, 75=left, 100=center.
  138. */
  139. LOCAL_FUNC void NEAR
  140. JsHat (POINTER *p, int reading, int base, int top, char *btn)
  141. {
  142.     if (reading <= base)
  143.         reading = 0;
  144.     else if (reading >= top)
  145.         reading = REF;
  146.     else
  147.         reading = muldiv (REF, reading - base, top - base);
  148.  
  149.     btn[4 + (reading + REF/8)/(REF/4)] = 1;
  150. }
  151.  
  152. /* Interpret the joystick reading as a 0-100.
  153.  * The 'base' parameter is interpreted as a fraction of the center reading.
  154. */
  155. LOCAL_FUNC void NEAR
  156. JsPos (POINTER *p, int channel, int reading, int sign, int base, int top,
  157.     int transfer)
  158. {
  159.     int    play;
  160.  
  161.     play = p->play[channel];
  162.  
  163.     if (reading <= (base += play))
  164.         reading = 0;
  165.     else if (reading >= (top -= play))
  166.         reading = REF;
  167.     else
  168.         reading = muldiv (REF, reading - base, top - base);
  169.  
  170.     if (sign)
  171.         reading = REF - reading;
  172.     p->a[channel] = (short)reading;
  173.     if (transfer)
  174.         p->l[channel] = (short)reading;
  175. }
  176.  
  177. LOCAL_FUNC int FAR
  178. JsaRead (POINTER *p, int transfer)
  179. {
  180.     STICK    s[1];
  181.     int    i, n;
  182.     char    btn[10];
  183.  
  184.     n = JS_X1|JS_Y1;
  185.     if (FOPTS & READA3)
  186.         n |= JS_Y2;
  187.     if (JsInput (0, s, FOPTS, (Ushort)n, (Ushort)FNREAD, (Ushort)FDELAY))
  188.         return (1);            /* reading failed */
  189.  
  190.     if (p->low[FA1F] > s->a[0])
  191.         p->low[FA1F] = s->a[0];
  192.     if (p->high[FA1F] < s->a[0])
  193.         p->high[FA1F] = s->a[0];
  194.     if (p->low[FA2F] > s->a[1])
  195.         p->low[FA2F] = s->a[1];
  196.     if (p->high[FA2F] < s->a[1])
  197.         p->high[FA2F] = s->a[1];
  198.     if (FOPTS & READA3) {
  199.         if (p->low[3] > s->a[3])
  200.             p->low[3] = s->a[3];
  201.         if (p->high[3] < s->a[3])
  202.             p->high[3] = s->a[3];
  203.     }
  204.  
  205.     if (!(FOPTS & CALIBRATED))
  206.         return (0);
  207.  
  208.     memset (btn, 0, sizeof (btn));
  209.  
  210.     JsSymm (p, FA1F, s->a[0], -FA1D, FA1BASE, FA1TOP, transfer);
  211.     JsSymm (p, FA2F, s->a[1],  FA2D, FA2BASE, FA2TOP, transfer);
  212.     if (FOPTS & READA3) {
  213.         if (FOPTS & HAT)
  214.             JsHat (p, s->a[3], FA4BASE, FA4TOP, btn);
  215.         else if (FOPTS & THROTTLE) {
  216.             JsPos (p, 3, s->a[3], FOPTS & THTDOWN,
  217.                 FA4BASE, FA4TOP, transfer);
  218.             if (!transfer)
  219.                 {}
  220.             else if (p->l[3] < p->c[3] - FA4IDLE)
  221.                 p->l[3] = (short)(muldiv (p->l[3],
  222.                             REFDETENT, p->c[3]));
  223.             else if (p->l[3] < p->c[3] + FA4IDLE)
  224.                 p->l[3] = REFDETENT;
  225.             else
  226.                 p->l[3] = (short)(REFDETENT
  227.                     + muldiv (REF-REFDETENT,
  228.                     p->l[3] - p->c[3], REF - p->c[3]));
  229.         }
  230.     }
  231.  
  232.     if (FOPTS & CHPRO) {
  233.         i = (s->b[0] << 3) | (s->b[1] << 2) | (s->b[2] << 1) | s->b[3];
  234.         switch (i) {
  235.         case 0x08:
  236.             btn[0] = 1;
  237.             break;
  238.         case 0x04:
  239.             btn[1] = 1;
  240.             break;
  241.         case 0x02:
  242.             btn[2] = 1;
  243.             break;
  244.         case 0x01:
  245.             btn[3] = 1;
  246.             break;
  247.         case 0x0c:
  248.             btn[7] = 1;
  249.             break;
  250.         case 0x0e:
  251.             btn[6] = 1;
  252.             break;
  253.         case 0x0d:
  254.             btn[5] = 1;
  255.             break;
  256.         case 0x0f:
  257.             btn[4] = 1;
  258.             break;
  259.         default:
  260.             break;
  261.         }
  262.         n = 8;
  263.     } else {
  264.         if (FOPTS & ZEROBUTTONS)
  265.             n = 0;
  266.         else {
  267.             n = (FOPTS & FOURBUTTONS) ? 4 : 2;
  268.  
  269.             for (i = 0; i < n; ++i)
  270.                 btn[i] = (char)s->b[i];
  271.         }
  272.         if (FOPTS & HAT) {
  273.             for (i = n; i < 4; ++i)
  274.                 btn[i] = p->btn[i] & 1;
  275.             n = 8;
  276.         }
  277.     }
  278.  
  279.     do_btns (p, btn, n);
  280.  
  281.     return (0);
  282. }
  283.  
  284. /* Calibrate joy-stick. Paddle and 'hat' must be at center!
  285. */
  286. LOCAL_FUNC int FAR
  287. JsaCal (POINTER *p)
  288. {
  289.     STICK    s[1];
  290.     int    m;
  291.  
  292.     m = JS_X1|JS_Y1;
  293.     if (FOPTS & (HAT|THROTTLE)) {
  294.         FOPTS |= READA3;
  295.         m |= JS_Y2;
  296.     }
  297.     m = JsInput (0, s, FOPTS, (Ushort)m, 10, 10);
  298.     if (m & JS_X1)
  299.         return (1);
  300.     if (!s->a[0])
  301.         return (2);
  302.     if (m & JS_Y1)
  303.         return (3);
  304.     if (!s->a[1])
  305.         return (4);
  306.  
  307.     FA1BASE = p->low[FA1F];
  308.     FA1TOP  = p->high[FA1F];
  309.     p->c[FA1F] = s->a[0];
  310.     p->play[FA1F] = muldiv (FA1TOP, FA1IDLE, 100);
  311.  
  312.     p->a[FA1F] = p->l[FA1F] = 0;
  313.     p->low [FA1F] = 0x7fff;
  314.     p->high[FA1F] = 0x0000;
  315.  
  316.     FA2BASE = p->low[FA2F];
  317.     FA2TOP  = p->high[FA2F];
  318.     p->c[FA2F] = s->a[1];
  319.     p->play[FA2F] = muldiv (FA2TOP, FA2IDLE, 100);
  320.  
  321.     p->a[FA2F] = p->l[FA2F] = 0;
  322.     p->low [FA2F] = 0x7fff;
  323.     p->high[FA2F] = 0x0000;
  324.  
  325.     if (FOPTS & READA3) {
  326.         if ((m & JS_Y2) || !s->a[3]) {
  327.             if (FOPTS & HAT)
  328.                 MsgEPrintf (50, "no analog hat");
  329.             else if (FOPTS & THROTTLE)
  330.                 MsgEPrintf (50, "no analog throttle");
  331.             FOPTS &= ~READA3;    /* failed */
  332.         } else if (FOPTS & HAT) {
  333.             MsgWPrintf (50, "using analog hat");
  334.             FA4BASE = p->low[3];
  335.             FA4TOP  = p->high[3];
  336.             p->c[3] = s->a[3];
  337.             p->play[3] = muldiv (FA4TOP, FA4IDLE, 100);
  338.             p->low [3] = 0x7fff;
  339.             p->high[3] = 0x0000;
  340.         } else if (FOPTS & THROTTLE) {
  341.             MsgWPrintf (50, "using analog throttle");
  342.             FA4BASE = p->low[3];
  343.             FA4TOP  = p->high[3];
  344.             p->play[3] = muldiv (FA4TOP, FA4IDLE, 100);
  345.             p->low [3] = 0x7fff;
  346.             p->high[3] = 0x0000;
  347.             JsPos (p, 3, s->a[3], FOPTS & THTDOWN,
  348.                 FA4BASE, FA4TOP, 0);
  349.             p->c[3] = p->a[3];
  350.             p->a[3] = p->l[3] = 0;
  351.         }
  352.     }
  353.  
  354.     FOPTS |= CALIBRATED;
  355.     return (0);
  356. }
  357.  
  358. LOCAL_FUNC void NEAR
  359. JsOptions (POINTER *p, char *options)
  360. {
  361.     long    l;
  362.  
  363.     if (get_arg (options, "count"))
  364.         FOPTS &= ~USETIMER;
  365.  
  366.     if (get_arg (options, "linear"))
  367.         FOPTS &= ~USELOG;
  368.  
  369.     if (get_narg (options, "rd=", &l))
  370.         FNREAD = 1;
  371.     else
  372.         FNREAD = (int)l;
  373.  
  374.     if (get_narg (options, "dly=", &l))
  375.         FDELAY = 1;
  376.     else
  377.         FDELAY = (int)l;
  378.  
  379.     if (get_narg (options, "ix1=", &l))
  380.         FA1IDLE = 10;
  381.     else
  382.         FA1IDLE = (int)l;
  383.     if (get_narg (options, "iy1=", &l))
  384.         FA2IDLE = 10;
  385.     else
  386.         FA2IDLE = (int)l;
  387. }
  388.  
  389. LOCAL_FUNC int FAR
  390. JsaInit (POINTER *p, char *options)
  391. {
  392.     int    i;
  393.     long    l;
  394.     int    ret;
  395.     char    *o;
  396.  
  397.     FOPTS &= ~(HAT|THROTTLE|FOURBUTTONS|ZEROBUTTONS);
  398.     FOPTS |= USETIMER|USELOG;
  399.  
  400.     JsOptions (p, options);
  401.  
  402.     if (get_narg (options, "ix2=", &l))
  403.         FA3IDLE = 10;
  404.     else
  405.         FA3IDLE = (int)l;
  406.     if (get_narg (options, "iy2=", &l))
  407.         FA4IDLE = 10;
  408.     else
  409.         FA4IDLE = (int)l;
  410.  
  411.     if (get_arg (options, "hat"))
  412.         FOPTS |= HAT;
  413.     else if (T(o = get_arg (options, "ttl"))) {
  414.         FOPTS |= THROTTLE;
  415.         if ('-' == *o)
  416.             FOPTS |= THTDOWN;
  417.     }
  418.  
  419.     if (get_arg (options, "zero"))
  420.         FOPTS |= ZEROBUTTONS;
  421.     else if (get_arg (options, "four"))
  422.         FOPTS |= FOURBUTTONS;
  423.     else if (get_arg (options, "chpro"))
  424.         FOPTS |= CHPRO;
  425.  
  426.     if (T(ret = initstick (0, options, FOPTS))) {
  427.         LogPrintf ("Astick init failed %d\n", ret);
  428.         return (ret);
  429.     }
  430.  
  431.     for (i = 0; i < 4; ++i) {
  432.         p->high[i] = 0x0000;
  433.         p->low [i] = 0x7fff;
  434.         p->c   [i] = 0x4000;
  435.     }
  436.  
  437.     JsaCal (p);        /* one for the road */
  438.     ret = JsaCal (p);
  439.     FOPTS &= ~CALIBRATED;
  440.     if (ret)
  441.         LogPrintf ("Astick cal failed %d\n", ret);
  442.     else {
  443.         MsgWPrintf (200, "Move the stick to all 4 egdes,");
  444.         MsgWPrintf (200, "   then center it.");
  445.         if (FOPTS & HAT) {
  446.             MsgWPrintf (200, "Try all hat positions,");
  447.             MsgWPrintf (200, "   then center it.");
  448.         }
  449.         if (FOPTS & THROTTLE) {
  450.             MsgWPrintf (200, "Move throttle to both ends,");
  451.             MsgWPrintf (200, "   then set to MIL detent.");
  452.         }
  453.         MsgWPrintf (200, "now hit 'x' to callibrate.");
  454.     }
  455.  
  456.     return (ret);
  457. }
  458.  
  459. LOCAL_FUNC void FAR
  460. JsaTerm (POINTER *p)
  461. {
  462.     termstick (0, FOPTS);
  463. }
  464.  
  465. LOCAL_FUNC int FAR
  466. JsCenter (POINTER *p)
  467. {
  468.     p->a[FA1F] = p->a[FA2F] = 0;
  469.     p->l[FA1F] = p->l[FA2F] = 0;
  470.  
  471.     return (0);
  472. }
  473.  
  474. LOCAL_FUNC int FAR
  475. JsbRead (POINTER *p, int transfer)
  476. {
  477.     STICK    s[1];
  478.     char    btn[2];
  479.  
  480.     if (JsInput (1, s, FOPTS, JS_X1|JS_Y1, (Ushort)FNREAD, (Ushort)FDELAY))
  481.         return (1);            /* reading failed */
  482.  
  483.     if (p->low[FA1F] > s->a[0])
  484.         p->low[FA1F] = s->a[0];
  485.     if (p->high[FA1F] < s->a[0])
  486.         p->high[FA1F] = s->a[0];
  487.     if (p->low[FA2F] > s->a[1])
  488.         p->low[FA2F] = s->a[1];
  489.     if (p->high[FA2F] < s->a[1])
  490.         p->high[FA2F] = s->a[1];
  491.  
  492.     if (!(FOPTS & CALIBRATED))
  493.         return (0);
  494.  
  495.     memset (btn, 0, sizeof (btn));
  496.  
  497.     JsSymm (p, FA1F, s->a[0], -FA1D, FA1BASE, FA1TOP, transfer);
  498.     JsSymm (p, FA2F, s->a[1],  FA2D, FA2BASE, FA2TOP, transfer);
  499.  
  500.     btn[0] = (char)s->b[0];
  501.     btn[1] = (char)s->b[1];
  502.     do_btns (p, btn, rangeof (btn));
  503.  
  504.     return (0);
  505. }
  506.  
  507. LOCAL_FUNC int FAR
  508. JsbCal (POINTER *p)
  509. {
  510.     STICK    s[1];
  511.     int    m;
  512.  
  513.     m = JS_X1|JS_Y1;
  514.     m = JsInput (1, s, FOPTS, (Ushort)m, 10, 10);
  515.     if (m & JS_X1)
  516.         return (1);
  517.     if (!s->a[0])
  518.         return (2);
  519.     if (m & JS_Y1)
  520.         return (3);
  521.     if (!s->a[1])
  522.         return (4);
  523.  
  524.     FA1BASE = p->low[FA1F];
  525.     FA1TOP  = p->high[FA1F];
  526.     p->c[FA1F] = s->a[0];
  527.     p->play[FA1F] = muldiv (FA1TOP, FA1IDLE, 100);
  528.  
  529.     p->a[FA1F] = p->l[FA1F] = 0;
  530.     p->low [FA1F] = 0x7fff;
  531.     p->high[FA1F] = 0x0000;
  532.  
  533.     FA2BASE = p->low[FA2F];
  534.     FA2TOP  = p->high[FA2F];
  535.     p->c[FA2F] = s->a[1];
  536.     p->play[FA2F] = muldiv (FA2TOP, FA2IDLE, 100);
  537.  
  538.     p->a[FA2F] = p->l[FA2F] = 0;
  539.     p->low [FA2F] = 0x7fff;
  540.     p->high[FA2F] = 0x0000;
  541.  
  542.  
  543.     FOPTS |= CALIBRATED;
  544.     return (0);
  545. }
  546.  
  547. LOCAL_FUNC int FAR
  548. JsbInit (POINTER *p, char *options)
  549. {
  550.     int    ret;
  551.  
  552.     FOPTS |= USETIMER;
  553.     JsOptions (p, options);
  554.  
  555.     if (initstick (1, options, FOPTS))
  556.         return (1);
  557.  
  558.     JsbCal (p);        /* one for the road */
  559.     FOPTS &= ~CALIBRATED;
  560.     ret = JsbCal (p);
  561.     FOPTS &= ~CALIBRATED;
  562.     if (ret)
  563.         LogPrintf ("Bstick cal failed %d\n", ret);
  564.     else {
  565.         MsgWPrintf (200, "Move the stick to all 4 egdes,");
  566.         MsgWPrintf (200, "   then center it.");
  567.         MsgWPrintf (200, "now hit 'x' to callibrate.");
  568.     }
  569.  
  570.     return (ret);
  571. }
  572.  
  573. LOCAL_FUNC void FAR
  574. JsbTerm (POINTER *p)
  575. {
  576.     termstick (1, FOPTS);
  577. }
  578.  
  579.  
  580. struct PtrDriver NEAR PtrAstick = {
  581.     "ASTICK",
  582.     0,
  583.     NULL,    /* extra */
  584.     JsaInit,
  585.     JsaTerm,
  586.     JsaCal,
  587.     JsCenter,
  588.     JsaRead,
  589.     std_key
  590. };
  591.  
  592. struct PtrDriver NEAR PtrBstick = {
  593.     "BSTICK",
  594.     0,
  595.     NULL,    /* extra */
  596.     JsbInit,
  597.     JsbTerm,
  598.     JsbCal,
  599.     JsCenter,
  600.     JsbRead,
  601.     std_key
  602. };
  603.  
  604. #undef PO
  605. #undef FA1D
  606. #undef FA1F
  607. #undef FA2D
  608. #undef FA2F
  609. #undef FNREAD
  610. #undef FDELAY
  611. #undef FA1IDLE
  612. #undef FA1BASE
  613. #undef FA1TOP
  614. #undef FA2IDLE
  615. #undef FA2BASE
  616. #undef FA2TOP
  617. #undef FA3IDLE
  618. #undef FA3BASE
  619. #undef FA3TOP
  620. #undef FA4IDLE
  621. #undef FA4BASE
  622. #undef FA4TOP
  623. #undef FOPTS
  624.  
  625. #undef REF
  626. #undef REFDETENT
  627.  
  628. #endif /* ifdef HAVE_JOYSTICK */
  629.